//==========================================================================//
//                                                                          //
//  BMP085 Library              Version 0.1                     March 2012  //
//                                                                          //
//  Written for the Arduino Duemilanove w/ ATmega328                        //
//                                                                          //
//  BMP085/I2C Arduino Library                                              //
//                                                                          //
//  Created by JFLagarde (jeanfrancoislagarde@hotmail.com)                  //
//                                                                          //
//  This file is part of OpenWS (http://code.google.com/p/openws/)          //
//                                                                          //
//==========================================================================//
//                                                                          //
//  Notes:                                                                  //
//                                                                          //
//                                                                          //
//==========================================================================//
//                                                                          //
//  Copyright 2012 Jean-Francois Lagarde (jeanfrancoislagarde@hotmail.com)  //
//  This program is distributed under the terms of                          //
//  the GNU General Public License                                          //
//                                                                          //
//  This program is free software: you can redistribute it and/or modify    //
//  it under the terms of the GNU General Public License as published by    //
//  the Free Software Foundation, either version 3 of the License, or       //
//  (at your option) any later version.                                     //
//                                                                          //
//  This program is distributed in the hope that it will be useful,         //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of          //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           //
//  GNU General Public License for more details.                            //
//                                                                          //
//  You should have received a copy of the GNU General Public License       //
//  along with this program.  If not, see <http://www.gnu.org/licenses/>.   //
//                                                                          //
//==========================================================================//

#include <Wire.h>
#include <BMP085.h>

BMP085::BMP085() {
    _dev_address = 0x77; //0x77 default I2C address
	
	_pressure_waittime[0] = 5; // These are maximum convertion times.
	_pressure_waittime[1] = 8; // It is possible to use pin EOC (End Of Conversion)
	_pressure_waittime[2] = 14;// to check if conversion is finished (logic 1) 
	_pressure_waittime[3] = 26;// or running (logic 0) insted of waiting for convertion times.
	
	_oss = MODE_STANDARD;
		
    _lastPressure = 0;
    _lastTemperature = 0;
	
	Wire.begin();
}

void BMP085::init() {
	init(MODE_STANDARD);
}
void BMP085::init(byte BMPMode) {
	calibrate();
	_oss = BMPMode;
}
void BMP085::read() {
	_lastTemperature = readTemperature();
	_lastPressure = readPressure();
}
int BMP085::getTemperature() {
	return _lastTemperature;
}
int BMP085::getPressure() {
	return _lastPressure;
}














//PRIVATE methods
void BMP085::calibrate() {
	readmem(0xAA, 2, _buff);
	ac1 = ((int)_buff[0] <<8 | ((int)_buff[1]));
	readmem(0xAC, 2, _buff);
	ac2 = ((int)_buff[0] <<8 | ((int)_buff[1]));
	readmem(0xAE, 2, _buff);
	ac3 = ((int)_buff[0] <<8 | ((int)_buff[1]));
	readmem(0xB0, 2, _buff);
	ac4 = ((unsigned int)_buff[0] <<8 | ((unsigned int)_buff[1]));
	readmem(0xB2, 2, _buff);
	ac5 = ((unsigned int)_buff[0] <<8 | ((unsigned int)_buff[1]));
	readmem(0xB4, 2, _buff);
	ac6 = ((unsigned int)_buff[0] <<8 | ((unsigned int)_buff[1])); 
	readmem(0xB6, 2, _buff);
	b1 = ((int)_buff[0] <<8 | ((int)_buff[1])); 
	readmem(0xB8, 2, _buff);
	b2 = ((int)_buff[0] <<8 | ((int)_buff[1])); 
	readmem(0xBA, 2, _buff);
	mb = ((int)_buff[0] <<8 | ((int)_buff[1]));
	readmem(0xBC, 2, _buff);
	mc = ((int)_buff[0] <<8 | ((int)_buff[1]));
	readmem(0xBE, 2, _buff);
	md = ((int)_buff[0] <<8 | ((int)_buff[1])); 
}

int BMP085::readTemperature(){
	long ut,x1,x2;

	//read Raw Temperature
	writemem(0xF4, 0x2E);
	delay(5);                                         // min. 4.5ms read Temp delay
	readmem(0xF6, 2, _buff); 
	ut = ((long)_buff[0] << 8 | ((long)_buff[1]));    // uncompensated temperature value

	// calculate temperature
	x1 = ((long)ut - ac6) * ac5 >> 15;
	x2 = ((long)mc << 11) / (x1 + md);
	b5 = x1 + x2;

	return ((b5+8)>>4);
}
int BMP085::readPressure() {
	long up,x1,x2,x3,b3,b6,p;
	unsigned long b4,b7;
	int32_t tmp; 

	//read Raw Pressure
	writemem(0xF4, 0x34+(_oss << 6));
	delay(_pressure_waittime[_oss]);    
	readmem(0xF6, 3, _buff);  
	up = ((((long)_buff[0] <<16) | ((long)_buff[1] <<8) | ((long)_buff[2])) >> (8-_oss)); // uncompensated pressure value

	// calculate true pressure
	b6 = b5 - 4000;             // b5 is updated by calcTrueTemperature().
	x1 = (b2* (b6 * b6 >> 12)) >> 11;
	x2 = ac2 * b6 >> 11;
	x3 = x1 + x2;
	tmp = ac1;
	tmp = (tmp * 4 + x3) << _oss;
	b3 = (tmp + 2) >> 2;
	x1 = ac3 * b6 >> 13;
	x2 = (b1 * (b6 * b6 >> 12)) >> 16;
	x3 = ((x1 + x2) + 2) >> 2;
	b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
	b7 = ((uint32_t)up - b3) * (50000 >> _oss);
	p = b7 < 0x80000000 ? (b7 << 1) / b4 : (b7 / b4) << 1;
	x1 = (p >> 8) * (p >> 8);
	x1 = (x1 * 3038) >> 16;
	x2 = (-7357 * p) >> 16;

	return ((int)((p + ((x1 + x2 + 3791) >> 4))/10));
}

void BMP085::writemem(uint8_t _addr, uint8_t _val) {
	Wire.beginTransmission(_dev_address);   // start transmission to device 
	Wire.write(_addr); // send register address
	Wire.write(_val); // send value to write  
	Wire.endTransmission(); // end transmission
}
void BMP085::readmem(uint8_t _addr, uint8_t _nbytes, uint8_t __buff[]) {
	Wire.beginTransmission(_dev_address); // start transmission to device 
	Wire.write(_addr); // sends register address to read from
	Wire.endTransmission(); // end transmission

	Wire.beginTransmission(_dev_address); // start transmission to device 
	Wire.requestFrom(_dev_address, _nbytes);// send data n-bytes read
	uint8_t i = 0; 

	while (Wire.available()) {
		__buff[i] = Wire.read(); // receive DATA
		i++;
	}
	Wire.endTransmission(); // end transmission
}